<template>
  <div class="json-viewer-container">
    <div class="json-viewer-wrapper">
      <div ref="lineNumbersRef" class="line-numbers">
        <div
          v-for="(line, index) in lineNumbers"
          :key="index"
          class="line-number"
        >
          {{ index + 1 }}
        </div>
      </div>
      <div
        ref="jsonContentRef"
        class="json-content"
        v-html="formattedJson"
        @scroll="handleScroll"
      ></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from "vue";

interface Props {
  data: any;
  height?: string;
}

const props = withDefaults(defineProps<Props>(), {
  height: "400px",
});

const lineNumbersRef = ref<HTMLElement>();
const jsonContentRef = ref<HTMLElement>();

// 格式化JSON并添加语法高亮
const formattedJson = computed(() => {
  if (!props.data) return "";

  try {
    const jsonString = JSON.stringify(props.data, null, 2);

    // 添加语法高亮
    return jsonString
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(
        /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
        function (match) {
          let cls = "json-number";
          if (/^"/.test(match)) {
            if (/:$/.test(match)) {
              cls = "json-key";
            } else {
              cls = "json-string";
            }
          } else if (/true|false/.test(match)) {
            cls = "json-boolean";
          } else if (/null/.test(match)) {
            cls = "json-null";
          }
          return '<span class="' + cls + '">' + match + "</span>";
        }
      );
  } catch (e) {
    return "无效的JSON数据";
  }
});

// 计算行号
const lineNumbers = computed(() => {
  if (!props.data) return [];

  try {
    const jsonString = JSON.stringify(props.data, null, 2);
    return jsonString.split("\n");
  } catch (e) {
    return ["1"];
  }
});

// 处理滚动事件，同步行号和内容滚动
const handleScroll = () => {
  if (lineNumbersRef.value && jsonContentRef.value) {
    lineNumbersRef.value.scrollTop = jsonContentRef.value.scrollTop;
  }
};
</script>

<style scoped lang="scss">
.json-viewer-container {
  height: v-bind(height);
  border: 1px solid #3c3c3c;
  border-radius: 4px;
  overflow: hidden;
}

.json-viewer-wrapper {
  display: flex;
  height: 100%;
  background-color: #1e1e1e;
}

.line-numbers {
  background-color: #2d2d2d;
  color: #858585;
  padding: 16px 8px 16px 12px;
  font-family: "Consolas", "Monaco", "Courier New", monospace;
  font-size: 14px;
  line-height: 1.5;
  text-align: right;
  user-select: none;
  border-right: 1px solid #3c3c3c;
  overflow-y: auto;
  min-width: 40px;

  /* 隐藏滚动条但保持滚动功能 */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */

  &::-webkit-scrollbar {
    display: none; /* Chrome/Safari */
  }
}

.line-number {
  height: 21px; /* 与内容行高保持一致 */
  line-height: 21px;
}

.json-content {
  flex: 1;
  color: #d4d4d4;
  padding: 16px;
  font-family: "Consolas", "Monaco", "Courier New", monospace;
  font-size: 14px;
  line-height: 1.5;
  overflow-x: auto;
  overflow-y: auto;
  white-space: pre;

  :deep(.json-key) {
    color: #9cdcfe;
    font-weight: normal;
  }

  :deep(.json-string) {
    color: #ce9178;
  }

  :deep(.json-number) {
    color: #b5cea8;
  }

  :deep(.json-boolean) {
    color: #569cd6;
  }

  :deep(.json-null) {
    color: #569cd6;
  }
}

// 滚动条样式
.json-content::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.json-content::-webkit-scrollbar-track {
  background: #2d2d2d;
}

.json-content::-webkit-scrollbar-thumb {
  background: #464647;
  border-radius: 4px;
}

.json-content::-webkit-scrollbar-thumb:hover {
  background: #5a5a5a;
}

// 确保行号和内容同步滚动
.json-viewer-wrapper {
  overflow: hidden;
}
</style>
